import { deepCopy } from '@/core';
import {
	IAbility,
	ICtrlActionResult,
	IEvent,
	IParam,
	IPortletControllerParams,
	IViewLogicInput,
} from '@/core/interface';
import {
	IMDCtrlAbility,
	IPortletAbility,
} from '@/core/interface/widgets/ability';
import { IPortletController } from '@/core/interface/widgets/controller';
import { PortletActionType } from '@/core/interface/widgets/event';
import { IPortletStore } from '@/core/interface/widgets/store';
import { DECtrlController } from './de-ctrl-controller';

/**
 * 门户部件控制器
 *
 * @export
 * @class PortletController
 * @extends {(DECtrlController<A | PortletEventActionType, IPortletStore>)}
 * @implements {IPortletController<T>}
 * @template A
 */
export class PortletController
	extends DECtrlController<PortletActionType, IPortletStore, IPortletAbility>
	implements IPortletController<IPortletStore, IPortletAbility>
{
	/**
	 * Creates an instance of DashboardController.
	 * @param {IPortletControllerParams<PortletActionType, IPortletAbility>} params
	 * @memberof PortletController
	 */
	public constructor(
		params: IPortletControllerParams<PortletActionType, IPortletAbility>
	) {
		super(params);
		this.ctrlInit(params);
	}

	/**
	 * 处理部件初始化
	 *
	 * @protected
	 * @param {IPortletControllerParams<PortletActionType, IPortletAbility>} params
	 * @memberof PortletController
	 */
	protected processCtrlInit(
		params: IPortletControllerParams<PortletActionType, IPortletAbility>
	) {
		super.processCtrlInit(params);
		Object.assign(this.store, {
			data: {},
			toolbarItems: this.model.toolbarItems || [],
			actions: this.model.actions || [],
		});
		this.initPortletArray();
	}

	/**
	 * 初始化后（对store做处理）除直接内容不抛出ctrl-init
	 *
	 * @protected
	 * @param {IPortletControllerParams<T, A>} params
	 * @memberof PortletController
	 */
	protected afterCtrlInit(
		params: IPortletControllerParams<PortletActionType, IPortletAbility>
	) {
		this.initStore();
		if (
			this.model.portletType === 'RAWITEM' ||
			this.model.portletType === 'HTML'
		) {
			this.evt.emit('ctrlInit', this.name, this.getAbility());
		}
	}

	/**
	 * 容器内门户部件数组
	 *
	 * @private
	 * @type {any[]}
	 * @memberof PortletController
	 */
	private portletArray: any[] = [];

	/**
	 * 初始化容器内门户部件数组
	 *
	 * @memberof PortletController
	 */
	protected initPortletArray() {
		const { portletArray } = this.model;
		if (portletArray && portletArray.length > 0) {
			this.portletArray.push(...portletArray);
		}
	}

	/**
	 * 处理门户部件
	 *
	 * @param {IEvent<string>} actionParam
	 * @memberof PortletController
	 */
	public handleComponentAction(actionParam: IEvent<string>): void {
		const { name, action, data } = actionParam;
		const ability = this.getSubAbility(name);
		switch (action) {
			case 'portletAction':
				this.handlePortletUIAction(data.event, data.logic, ability);
				break;
		}
	}

	/**
	 * 处理portlet界面行为
	 *
	 * @param {MouseEvent} event 事件源
	 * @param {IViewLogicInput} logic 逻辑
	 * @memberof PortletController
	 */
	private handlePortletUIAction(
		event: MouseEvent,
		logic: IViewLogicInput,
		ability: IAbility
	): void {
		const { context, viewParams } = this.store;
		App.getViewLogicHelper().executeViewLogic(
			context,
			viewParams,
			this.getData(),
			event,
			ability,
			logic
		);
	}

	/**
	 * 设置子能力
	 *
	 * @param {string} name
	 * @param {IAbility} subAbility
	 * @memberof PortletController
	 */
	public setSubAbility(name: string, subAbility: IAbility) {
		this.subAbilityCenter.set(name, subAbility);
		// 门户容器的话等内部所有门户部件抛出能力再初始化完成
		if (this.portletArray.length > 0) {
			if (this.subAbilityCenter.size == this.portletArray.length) {
				this.evt.emit('ctrlInit', this.name, this.getAbility());
			}
		} else {
			// 不是容器的话则直接初始化完成
			this.evt.emit('ctrlInit', this.name, this.getAbility());
		}
	}

	/**
	 * 加载子部件
	 *
	 * @memberof PortletController
	 */
	public load(opts: IParam = {}): Promise<ICtrlActionResult> {
		return new Promise((resolve: any, reject: any) => {
			const promiseArray: any = [];
			// 容器的话需要内部全部加载
			if (this.portletArray.length > 0) {
				this.portletArray.forEach((item: any) => {
					const ability = this.getPortletCtrlAbility(item.name.toLowerCase());
					if (ability) {
						const promise = ability.load(opts);
						promiseArray.push(promise);
					}
				});
			} else {
				// 不是容器的话直接获取自身能力
				const ability = this.getPortletCtrlAbility(this.name.toLowerCase());
				if (ability) {
					const promise = ability.load(opts);
					promiseArray.push(promise);
				}
			}
			const { context } = this.store;
			const tempContext = deepCopy(context);
			this.beforeAsyncAction('load', tempContext, {});
			Promise.all(promiseArray)
				.then((resArray: any) => {
					let _data: any = [];
					resArray.forEach((response: any, resIndex: number) => {
						if (!response || !response.ok) {
							this.afterAsyncAction('load', response);
							return;
						}
						_data.push(response.rowData);
					});
					let result = { ok: true, rowData: _data };
					resolve(result);
					this.afterAsyncAction('load', _data);
				})
				.catch((response: any) => {
					reject(response);
				});
		});
	}

	/**
	 * 获取门户部件能力
	 *
	 * @protected
	 * @return {*}  {(IMDCtrlAbility)}
	 * @memberof PortletController
	 */
	protected getPortletCtrlAbility(name: string): IMDCtrlAbility {
		return this.getSubAbility<IMDCtrlAbility>(name);
	}

	/**
	 * 获取部件能力
	 *
	 * @return {*}  {A}
	 * @memberof PortletController
	 */
	public getAbility(): IPortletAbility {
		return {
			...super.getAbility(),
			load: this.load.bind(this),
		};
	}
}
